/**
 * $version:  0.1 
 * $Date: 2011-01-21 
 *
 * Copyright (C) 2010-2011 Jawa Software. All rights reserved.
 *
 */

package org.jawa.util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.TimeZone;

import org.jawa.database.DbConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 工具类
 * 
 * @author Y-N
 */
public class JawaGlobals {

	private static final Logger Log = LoggerFactory.getLogger(JawaGlobals.class);

	// 系统工作目录
	private static String home = null;

	// 系统配置文件名称
	private static String JAWA_CONFIG_FILENAME = "/jawa.xml";

	// 系统的 XML配制文件.
	private static XMLProperties xmlProperties = null;

	// 系统参数
	private static JawaProperties properties = null;

	// 系统运行状态
	private static ApplicationState applicationState = null;

	// 系统参数文件加载状态
	public static boolean failedLoading = false;
	private static Locale locale = null;
	private static TimeZone timeZone = null;

	private static DateFormat dateFormat = null;
	private static DateFormat dateTimeFormat = null;
	private static DateFormat timeFormat = null;

	/**
	 * 返回系统工作的目录.
	 * 
	 * @return 系统工作的目录.
	 */
	public static String getHomeDirectory() {
		return home;
	}

	/**
	 * 设置系统工作的目录,系统对此目录需要有读与写的权限.
	 * 
	 * @param pathname
	 *            系统工作的目录.
	 */
	public static void setHomeDirectory(String pathname) {
		File mh = new File(pathname);
		if (!mh.exists()) {
			Log.error("错误 - 指定的目录不存在 (" + pathname + ")");
		} else if (!mh.canRead() || !mh.canWrite()) {
			Log.error("错误 - 启动系统的用户对目录没有读或写的权限 " + "(" + pathname + "). " + "请将读和写的权限赋予启动系统的用户.");
		} else {
			home = pathname;
		}
	}

	/**
	 * 返回配制文件中的一个元素值。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * 通过getProperties("foo.bar.prop")方法将返回"some value"。 如果同样名称的元素存在多个，将只返回第一个。
	 * 
	 * @param name
	 *            元素名称.
	 * @return 元素值.
	 */
	public static String getXMLProperty(String name) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}

		if (xmlProperties == null) {
			return null;
		}

		return xmlProperties.getProperty(name);
	}

	/**
	 * 返回配制文件中的一个元素值。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * 如果指定的元素不存在，将返回默认值。
	 * 
	 * @param name
	 *            元素名称.
	 * @param defaultValue
	 *            默认值.
	 * @return 元素值.
	 */
	public static String getXMLProperty(String name, String defaultValue) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}

		if (xmlProperties == null) {
			return null;
		}

		String value = xmlProperties.getProperty(name);
		if (value == null) {
			value = defaultValue;
		}
		return value;
	}

	/**
	 * 返回配制文件中的一个整型类型的元素值,如果指定的元素不存在将返回默认值。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * 如果指定的元素值不存在，将返回默认值。
	 * 
	 * @param name
	 *            元素名称.
	 * @param defaultValue
	 *            默认值.
	 * @return 元素值.
	 */
	public static int getXMLProperty(String name, int defaultValue) {
		String value = getXMLProperty(name);
		if (value != null) {
			try {
				return Integer.parseInt(value);
			} catch (NumberFormatException nfe) {
				// 忽略.
			}
		}
		return defaultValue;
	}

	/**
	 * 返回配制文件中的一个布尔类型的元素值,如果指定的元素不存在将返回默认值。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * 如果指定的元素不存在，将返回默认值。
	 * 
	 * @param name
	 *            元素名称.
	 * @param defaultValue
	 *            默认值.
	 * @return 如果指定的属性值存在并且像 <tt>"true"</tt> (不区分大小写)则返回true,否则返回false.
	 */
	public static boolean getXMLProperty(String name, boolean defaultValue) {
		String value = getXMLProperty(name);
		if (value != null) {
			return Boolean.valueOf(value);
		}
		return defaultValue;
	}

	/**
	 * 
	 * 返回配制文件中的指定元素名称下的多个元素值列表。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * </p>
	 * 元素在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *         &lt;prop&gt;other value&lt;/prop&gt;
	 *         &lt;prop&gt;last value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * 通过getProperties("foo.bar.prop")方法将返回{"some value",
	 * "other value","last value"}。
	 * 
	 * 
	 * @param name
	 *            元素名称
	 * @return 所有元素值
	 */
	public static String[] getXMLPropertys(String name) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}

		if (xmlProperties == null) {
			return null;
		}

		return xmlProperties.getProperties(name);
	}

	/**
	 * 返回配制文件中指定父元素名称下所有的直接子元素的值列表。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * <p>
	 * 假如存以以下元素 <tt>X.Y.A</tt>, <tt>X.Y.B</tt> , <tt>X.Y.C</tt> ,
	 * <tt>X.Y.C.D</tt> , 当通过元素名称 <tt>X.Y</tt> 获取元素值列表时将返回 <tt>A</tt>,
	 * <tt>B</tt>, <tt>C</tt>。 对于<tt>C.D</tt>将不会返回。
	 * <p>
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * 
	 * @param parent
	 *            父元素名称.
	 * @return 元素值列表.
	 */
	public static List getChildrenXMLProperties(String parent) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}

		if (xmlProperties == null) {
			return Collections.EMPTY_LIST;
		}

		String[] propNames = xmlProperties.getChildrenPropertieNames(parent);
		List<String> values = new ArrayList<String>();
		for (String propName : propNames) {
			String value = getXMLProperty(parent + "." + propName);
			if (value != null) {
				values.add(value);
			}
		}

		return values;

	}

	/**
	 * 设置配制文件中指定元素名称的元素值。如果指定的元素不存在，将创建一个新的元素。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * 
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * @param name
	 *            元素名称.
	 * @param value
	 *            元素值.
	 */
	public static void setXMLProperty(String name, String value) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}

		if (xmlProperties != null) {
			xmlProperties.setProperty(name, value);
		}
	}

	/**
	 * 
	 * 一次设置配制文件中多个元素值。如果指定的元素不存在，将创建一个新的元素。
	 * <p>
	 * 配制文件在系统目录<tt>home</tt>下，以 <tt>JAWA_CONFIG_FILENAME</tt>名称的文件中。
	 * <p>
	 * 
	 * 元素 "foo.bar.prop" 在 XML 文件中定义如下所示:
	 * 
	 * <pre>
	 * &lt;foo&gt;
	 *     &lt;bar&gt;
	 *         &lt;prop&gt;some value&lt;/prop&gt;
	 *     &lt;/bar&gt;
	 * &lt;/foo&gt;
	 * </pre>
	 * 
	 * @param propertyMap
	 *            元素值列表，key 键为元素名称.
	 */

	public static void setXMLProperties(Map<String, String> propertyMap) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}

		if (xmlProperties != null) {
			xmlProperties.setProperties(propertyMap);
		}
	}

	/**
	 * 删除配制文件中的一个元素。如果对应的元素不存在，则什么也不做。
	 * 
	 * @param name
	 *            元素名称.
	 */
	public static void deleteXMLProperty(String name) {
		if (xmlProperties == null) {
			loadSetupProperties();
		}
		xmlProperties.deleteProperty(name);
	}

	/**
	 * 返回一个系统中的一个属性值.
	 * 
	 * @param name
	 *            属性名称.
	 * @return 属性值.
	 */
	public static String getProperty(String name) {
		if (properties == null) {
			if (isSetupMode()) {
				return null;
			}
			properties = JawaProperties.getInstance();
		}
		return properties.get(name);
	}

	/**
	 * 
	 * 返回一个属性值,如果指定的属性不存在返回默认值.
	 * 
	 * @param name
	 *            属性名称.
	 * @param defaultValue
	 *            如果指定的属性不存在,返回的默认值.
	 * @return 属性值.
	 */
	public static String getProperty(String name, String defaultValue) {
		if (properties == null) {
			if (isSetupMode()) {
				return defaultValue;
			}
			properties = JawaProperties.getInstance();
		}
		String value = properties.get(name);
		if (value != null) {
			return value;
		} else {
			return defaultValue;
		}
	}

	/**
	 * 返回一个整型的属性值,如果指定的属性不存在返回默认值.
	 * 
	 * @param name
	 *            属性名称.
	 * @param defaultValue
	 *            如果指定的属性不存在,返回的默认值.
	 * @return 属性值.
	 */
	public static int getIntProperty(String name, int defaultValue) {
		String value = getProperty(name);
		if (value != null) {
			try {
				return Integer.parseInt(value);
			} catch (NumberFormatException nfe) {
				// 忽略.
			}
		}
		return defaultValue;
	}

	/**
	 * 返回一个长整型的属性值,如果指定的属性不存在返回默认值.
	 * 
	 * @param name
	 *            属性名称.
	 * @param defaultValue
	 *            如果指定的属性不存在,返回的默认值.
	 * @return 属性值.
	 */
	public static long getLongProperty(String name, long defaultValue) {
		String value = getProperty(name);
		if (value != null) {
			try {
				return Long.parseLong(value);
			} catch (NumberFormatException nfe) {
				// 忽略.
			}
		}
		return defaultValue;
	}

	/**
	 * 返回一个布尔型的属性值.
	 * 
	 * @param name
	 *            属性名称.
	 * @return 如果指定的属性值存在并且像 <tt>"true"</tt> (不区分大小写)则返回true,否则返回false
	 */
	public static boolean getBooleanProperty(String name) {
		return Boolean.valueOf(getProperty(name));
	}

	/**
	 * 返回一个布尔型的属性值,如果指定的属性不存在返回默认值.
	 * 
	 * 
	 * @param name
	 *            属性名称.
	 * @param defaultValue
	 *           如果指定的属性不存在,返回的默认值.
	 * @return 如果指定的属性值存在并且像 <tt>"true"</tt> (不区分大小写)则返回true,否则返回false.
	 */
	public static boolean getBooleanProperty(String name, boolean defaultValue) {
		String value = getProperty(name);
		if (value != null) {
			return Boolean.valueOf(value);
		} else {
			return defaultValue;
		}
	}

	/**
	 * 返回父属性下的所有子属性名称. 例如存在以下属性 <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and
	 * <tt>X.Y.C</tt> , 调用 <tt>X.Y</tt> 将返回<tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and
	 * <tt>X.Y.C</tt>. 但是本属性不会返回子属性的子属性名称.
	 * 
	 * @param parent
	 *            父属性名称.
	 * @return 子属性名称列表.
	 */
	public static List<String> getPropertyNames(String parent) {
		if (properties == null) {
			if (isSetupMode()) {
				return new ArrayList<String>();
			}
			properties = JawaProperties.getInstance();
		}
		return new ArrayList<String>(properties.getChildrenNames(parent));
	}

	/**
	 * 返回父属性下的所有子属性值. 例如存在以下属性 <tt>X.Y.A</tt>, <tt>X.Y.B</tt>, and
	 * <tt>X.Y.C</tt> , 调用 <tt>X.Y</tt> 将返回<tt>X.Y.A</tt>, <tt>X.Y.B</tt>, 以及
	 * <tt>X.Y.C</tt>的属性值. 但是本属性不会返回子属性的子属性.
	 * 
	 * @param parent
	 *            父属性名称.
	 * @return 隶属于父属性的子属性的值.
	 */
	public static List<String> getProperties(String parent) {
		if (properties == null) {
			if (isSetupMode()) {
				return new ArrayList<String>();
			}
			properties = JawaProperties.getInstance();
		}

		Collection<String> propertyNames = properties.getChildrenNames(parent);
		List<String> values = new ArrayList<String>();
		for (String propertyName : propertyNames) {
			String value = getProperty(propertyName);
			if (value != null) {
				values.add(value);
			}
		}

		return values;
	}

	/**
	 * 返回系统中所有属性名称.
	 * 
	 * @return 属性名称列表.
	 */
	public static List<String> getPropertyNames() {
		if (properties == null) {
			if (isSetupMode()) {
				return new ArrayList<String>();
			}
			properties = JawaProperties.getInstance();
		}
		return new ArrayList<String>(properties.getPropertyNames());
	}

	/**
	 * 设置一个属性值，如果不存在则创建一个.
	 * 
	 * @param name
	 *            属性名称.
	 * @param value
	 *            属性值.
	 */
	public static void setProperty(String name, String value) {
		if (properties == null) {
			if (isSetupMode()) {
				return;
			}
			properties = JawaProperties.getInstance();
		}
		properties.put(name, value);
	}

	/**
	 * 设置多个属性值.
	 * 
	 * @param propertyMap
	 *            多个属性值, key 键做为属性名称.
	 */
	public static void setProperties(Map<String, String> propertyMap) {
		if (properties == null) {
			if (isSetupMode()) {
				return;
			}
			properties = JawaProperties.getInstance();
		}

		properties.putAll(propertyMap);
	}

	/**
	 * 删除一个属性值.所有的子属性也将被删除.
	 * 
	 * @param name
	 *            属性名称.
	 */
	public static void deleteProperty(String name) {
		if (properties == null) {
			if (isSetupMode()) {
				return;
			}
			properties = JawaProperties.getInstance();
		}
		properties.remove(name);
	}

	/**
	 * 设置系统配置文件的名称。默认为"jawa.xml".
	 * 
	 * @param configName
	 *            配置文件名称.
	 */
	public static void setConfigName(String configName) {
		JAWA_CONFIG_FILENAME = configName;
	}

	/**
	 * 返回系统配置文件名称.
	 * 
	 * @return 配置文件名称.
	 */
	static String getConfigName() {
		return JAWA_CONFIG_FILENAME;
	}

	/**
	 * 加载系统配制文件.
	 * <p>
	 * 属性配制文件在以 <tt>CONFIG_FILENAME</tt>为名称的文件中。
	 * <p>
	 */
	private synchronized static void loadSetupProperties() {
		if (xmlProperties == null) {
			if (home == null && failedLoading) {
				failedLoading = true;
				StringBuilder msg = new StringBuilder();
				msg.append("严重错误! 加载系统配制文件出错!");
				System.err.println(msg.toString());
			} else {
				try {
					if (home == null) {
						URL resource = JawaGlobals.class.getResource(JAWA_CONFIG_FILENAME);
						if (null != resource) {
							xmlProperties = new XMLProperties(resource.getFile());
						} else {
							failedLoading = true;
							Log.error("配置文件不存在。");
						}
					} else {
						xmlProperties = new XMLProperties(home + File.separator + getConfigName());
					}
				} catch (IOException ioe) {
					Log.error(ioe.getMessage(), ioe);
					failedLoading = true;
				}
			}
		}
	}

	/**
	 * 判断是否已经正确安装。如果是 false 意味着安装已完成.如果是true 意味着没有安装完成。
	 * 
	 * @return 返回<tt>Boolean 型，true：表示已正确安装，false：表示未安装</tt>
	 */
	public static Boolean isSetupMode() {
		if (Boolean.valueOf(JawaGlobals.getXMLProperty("setup"))) {
			return false;
		}
		// 检查数据库是否已配制完成，并正常运行.
		if (DbConnectionManager.getConnectionProvider() == null) {
			return true;
		}
		Connection con = null;
		PreparedStatement pstmt = null;
		try {
			con = DbConnectionManager.getConnection();
		} catch (SQLException e) {
			// 数据库没有正确配置，需要重装安装
			return true;
		} finally {
			DbConnectionManager.closeConnection(pstmt, con);
		}
		return false;
	}

	/**
	 * 获取当前应用的运行状态。
	 * 
	 * @return 返回 <tt>ApplicationState </tt>系统运行状态。
	 */
	public static ApplicationState getApplicationState() {
		if (null == applicationState) {
			applicationState = ApplicationState.SETUP;
			if (xmlProperties == null) {
				loadSetupProperties();
			}
			if (xmlProperties != null) {
				try {
					String applicationStateValue = xmlProperties.getProperty("applicationState");
					if (applicationStateValue == null || "".equals(applicationStateValue)) {
						applicationState = ApplicationState.SETUP;
					} else {
						if ("SETUP".equalsIgnoreCase(applicationStateValue)) {
							applicationState = ApplicationState.SETUP;
						} else if ("RUNNING".equalsIgnoreCase(applicationStateValue)) {
							applicationState = ApplicationState.RUNNING;
						} else if ("RESTART".equalsIgnoreCase(applicationStateValue)) {
							applicationState = ApplicationState.RESTART;
						} else {
							applicationState = ApplicationState.SETUP;
						}
					}
				} catch (Exception e) {
					applicationState = ApplicationState.SETUP;
				}
			}
		}
		return applicationState;
	}

	/**
	 * 设置当前应用的运行状态。
	 * 
	 * @param applicationState
	 *            系统状态。
	 */
	public static void setApplicationState(ApplicationState state) {
		applicationState = state;
		setXMLProperty("applicationState", applicationState.name());
	}

	/**
	 * 获取系统配置文件中的locale属性的值,如果为空，返回系统的默认LOCAL. </br>
	 * 用于国际化使用的LOCAL属性配置的语言和国家代码 </br>
	 * 默认属性依赖当前系统的语言 - Locale.getDefault().
	 *
	 * @return 返回<tt> Locale 对象</tt>
	 */
	public static Locale getLocale() {
		if (locale == null) {
			if (xmlProperties != null) {
				String[] localeArray;
				String localeProperty = xmlProperties.getProperty("locale");
				if (localeProperty != null) {
					localeArray = localeProperty.split("_");
				} else {
					localeArray = new String[] { "", "" };
				}

				String language = localeArray[0];
				if (language == null) {
					language = "";
				}
				String country = "";
				if (localeArray.length == 2) {
					country = localeArray[1];
				}
				// If no locale info is specified, return the system default Locale.
				if (language.equals("") && country.equals("")) {
					locale = Locale.getDefault();
				} else {
					locale = new Locale(language, country);
				}
			} else {
				return Locale.getDefault();
			}
		}
		return locale;
	}

	/**
	 * 设置系统配置文件中的locale属性的值
	 * 
	 * @param newLocale
	 *            <tt>Locale 对象</tt>
	 */
	public static void setLocale(Locale newLocale) {
		locale = newLocale;
		setXMLProperty("locale", locale.toString());
		// Reset the date formatter objects
		timeFormat = null;
		dateFormat = null;
		dateTimeFormat = null;
	}

	/**
	 * 获取当前时区 default time zone.
	 * 
	 * @return <tt>返回 TimeZone 类型</tt>
	 */
	public static TimeZone getTimeZone() {
		if (timeZone == null) {
			if (properties != null) {
				String timeZoneID = (String) xmlProperties.getProperty("locale.timeZone");
				if (timeZoneID == null) {
					timeZone = TimeZone.getDefault();
				} else {
					timeZone = TimeZone.getTimeZone(timeZoneID);
				}
			} else {
				return TimeZone.getDefault();
			}
		}
		return timeZone;
	}

	/**
	* Sets the global time zone used by Jive. The default time zone is the VM's
	* time zone.
	*
	* @param newTimeZone Time zone to set.
	*/
	public static void setTimeZone(TimeZone newTimeZone) {
		timeZone = newTimeZone;
		if (timeFormat != null) {
			timeFormat.setTimeZone(timeZone);
		}
		if (dateFormat != null) {
			dateFormat.setTimeZone(timeZone);
		}
		if (dateTimeFormat != null) {
			dateTimeFormat.setTimeZone(timeZone);
		}
		setProperty("locale.timeZone", timeZone.getID());
	}

	/**
	 * Formats a Date object to return a time using the global locale.
	 *
	 * @param date the Date to format.
	 * @return a String representing the time.
	 */
	public static String formatTime(Date date) {
		if (timeFormat == null) {
			if (properties != null) {
				timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT, getLocale());
				timeFormat.setTimeZone(getTimeZone());
			} else {
				DateFormat instance = DateFormat.getTimeInstance(DateFormat.SHORT, getLocale());
				instance.setTimeZone(getTimeZone());
				return instance.format(date);
			}
		}
		return timeFormat.format(date);
	}

	/**
	 * Formats a Date object to return a date using the global locale.
	 *
	 * @param date the Date to format.
	 * @return a String representing the date.
	 */
	public static String formatDate(Date date) {
		if (dateFormat == null) {
			if (properties != null) {
				dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
				dateFormat.setTimeZone(getTimeZone());
			} else {
				DateFormat instance = DateFormat.getDateInstance(DateFormat.MEDIUM, getLocale());
				instance.setTimeZone(getTimeZone());
				return instance.format(date);
			}
		}
		return dateFormat.format(date);
	}

	/**
	 * Formats a Date object to return a date and time using the global locale.
	 *
	 * @param date the Date to format.
	 * @return a String representing the date and time.
	 */
	public static String formatDateTime(Date date) {
		if (dateTimeFormat == null) {
			if (properties != null) {
				dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, getLocale());
				dateTimeFormat.setTimeZone(getTimeZone());
			} else {
				DateFormat instance = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, getLocale());
				instance.setTimeZone(getTimeZone());
				return instance.format(date);
			}
		}
		return dateTimeFormat.format(date);
	}
	
	
	/**
	 * 将类似 en、en_US、或en_US_win的语言环境转换为java的语言环境(Locale)对象，如果转换失败则返回null.
     *
     * @param localeCode 要转换成JAVA语言环境(Locale)对象的字符串语言代码. 详情请参考 {@link java.util.Locale}.
     * @return 返回与之匹配的Java环境对象, 或返回 <tt>null</tt>.                  
     */
    public static Locale localeCodeToLocale(String localeCode) {
        Locale locale = null;
        if (localeCode != null) {
            String language = null;
            String country = null;
            String variant = null;
            StringTokenizer tokenizer = new StringTokenizer(localeCode, "_");
            if (tokenizer.hasMoreTokens()) {
                language = tokenizer.nextToken();
                if (tokenizer.hasMoreTokens()) {
                    country = tokenizer.nextToken();
                    if (tokenizer.hasMoreTokens()) {
                        variant = tokenizer.nextToken();
                    }
                }
            }
            locale = new Locale(language,
                    ((country != null) ? country : ""),
                    ((variant != null) ? variant : ""));
        }
        return locale;
    }
    

}